#ifndef WEBBRIDGE_H
#define WEBBRIDGE_H
#include "bridgeobjectmanager.h"
#include <QJsonObject>
#include <QPointer>
#include <QWebEngineScript>

QT_BEGIN_NAMESPACE
class QWebEnginePage;
QT_END_NAMESPACE

class WebInterface;

class WebBridge : public QObject
{
    Q_OBJECT
public:
    WebBridge(QWidget* view, QWebEnginePage* page, WebInterface* web_interface,
              BridgeObjectManager* object_mgr, QObject* parent = nullptr);
    ~WebBridge() override;

    // 方法过滤器
    const BridgeMethodFilter& methodFilter() const { return method_filter_; }
    void setMethodFilter(const BridgeMethodFilter& f) { method_filter_ = f; }

    // 注入脚本
    bool inject(const QString& object_name, const QString& script_name,
                const QString& prefix = "YCQtBridge") const;

    // 回调js方法
    bool invokeJsCallback(const QString& callback, const QString& args, bool keep = false);

    // 通知js事件(Client发生的)
    void notifyClientEvent(const QString& object_id, const QString& event_name,
                           const QString& args);

    // 调用js方法
    void invokeJsMethod(const QString& method, const QString& args, const QString& success_callback,
                        const QString& failure_callback, const QString& sender_id);

    // 注入qwebchannel.js
    static bool injectWebChannelScript(QWebEnginePage& page);

    // 注入bridge对象
    static bool injectObject(QWebEnginePage& page, QObject* bridge, const QString& object_name,
                             const QList<QString>& method_names, const QString& script_name,
                             const QString& prefix = "YCQtBridge");

    // 注入脚本代码
    static bool
    injectScript(QWebEnginePage& page, const QString& source_code, const QString& script_name,
                 quint32 world_id = QWebEngineScript::MainWorld,
                 QWebEngineScript::InjectionPoint point = QWebEngineScript::DocumentCreation);

    // 生成脚本代码
    static QString scriptSourceCode(const QMetaMethod& method, const QString& object_name,
                                    const QString& prefix);

    // 获得方法
    static QMetaMethod metaMethod(const QMetaObject* object, const QString& name);
    static QList<QMetaMethod> metaMethods(const QMetaObject* object, const QList<QString>& names);

    // 生成回调参数
    static QString createResponse(const QJsonValue& data, int status = 0,
                                  const QString& message = QString());

    // 调用js方法
    static void invokeJsMethod(QWebEnginePage& page, const QString& framework_name,
                               const QString& method, const QString& args,
                               const QString& success_callback, const QString& failure_callback,
                               const QString& id);

    // 生成script name
    static QString genScriptName();

public Q_SLOTS:
    // 调用Client的方法
    void invokeMethod(const QString& method_name, const QString& args,
                      const QString& success_callback, const QString& failure_callback,
                      const QString& sender_id);
    // 调用回调
    void invokeCallback(const QString& callback, const QString& args);
    // 通知JS发生的事件
    void notifyEvent(const QString& event_type, const QString& args);

Q_SIGNALS:
    void methodInvoked(const QString& object_id, const QString& method, const QString& args,
                       const QString& uniform_success_callback,
                       const QString& uniform_failure_callback, const QString& sender_id,
                       QWidget* sender_view);
    void callbackInvoked(const QString& callback, const QString& args);
    void eventNotified(const QString& object_id, const QString& event_type, const QString& args);

private:
    QPointer<QWidget> view_;
    QWebEnginePage* page_;
    WebInterface* web_interface_;
    BridgeObjectManager* object_mgr_;
    QString bridge_object_id_;
    BridgeMethodFilter method_filter_;
};

#endif // WEBBRIDGE_H
